#include "Box.h"
#include <QtOpenGL/qgl.h>
#include <float.h>
#include <math.h>

Box::Box()
{
    initialized = false;
}

Box::Box(const Point& minimum, const Point& maximum)
{
    minb = minimum;
    maxb = maximum;
    initialized = true;

}

Box::Box(const Box &b1, const Box &b2)
{
    init(b1.minb);
    update(b1.maxb);
    update(b2.minb);
    update(b2.maxb);
    initialized = true;
}

float Box::diagonal() const
{
    return (maxb-minb).length();
}

vector<Plane> Box::Planes() const
{
    vector<Plane> planes(6);
    planes[0] = Plane(Vector(-1, 0, 0),-fabs(minb.x));
    planes[1] = Plane(Vector( 1, 0, 0),-fabs(maxb.x));
    planes[2] = Plane(Vector( 0,-1, 0),-fabs(minb.y));
    planes[3] = Plane(Vector( 0, 1, 0),-fabs(maxb.y));
    planes[4] = Plane(Vector( 0, 0,-1),-fabs(minb.z));
    planes[5] = Plane(Vector( 0, 0, 1),-fabs(maxb.z));
    return planes;
}





void Box::update(const Point& p)
{
    if (initialized) {
        if (p.x < minb.x) minb.x=p.x;

        if (p.y < minb.y) minb.y=p.y;

        if (p.z < minb.z) minb.z=p.z;

        if (p.x > maxb.x) maxb.x=p.x;

        if (p.y > maxb.y) maxb.y=p.y;

        if (p.z > maxb.z) maxb.z=p.z;
    }
    else {
        init(p);
    }
}


void Box::init(const Point& p)
{
    minb = p;
    maxb = p;
    initialized = true;
}

void Box::Render() const
{
    glLineWidth(1.0);
    Render(1.0, 1.0, 1.0);
}

void Box::Render(double r, double g, double b) const
{
    glColor3f(r, g, b);
    glBegin(GL_LINES);
    //glBegin(GL_POLYGON);
    glVertex3f(minb.x, minb.y, minb.z);
    glVertex3f(maxb.x, minb.y, minb.z);

    glVertex3f(maxb.x, minb.y, minb.z);
    glVertex3f(maxb.x, maxb.y, minb.z);

    glVertex3f(maxb.x, maxb.y, minb.z);
    glVertex3f(minb.x, maxb.y, minb.z);

    glVertex3f(minb.x, maxb.y, minb.z);
    glVertex3f(minb.x, minb.y, minb.z);

    glVertex3f(minb.x, minb.y, maxb.z);
    glVertex3f(maxb.x, minb.y, maxb.z);

    glVertex3f(maxb.x, minb.y, maxb.z);
    glVertex3f(maxb.x, maxb.y, maxb.z);

    glVertex3f(maxb.x, maxb.y, maxb.z);
    glVertex3f(minb.x, maxb.y, maxb.z);

    glVertex3f(minb.x, maxb.y, maxb.z);
    glVertex3f(minb.x, minb.y, maxb.z);

    glVertex3f(minb.x, maxb.y, minb.z);
    glVertex3f(minb.x, maxb.y, maxb.z);

    glVertex3f(maxb.x, maxb.y, minb.z);
    glVertex3f(maxb.x, maxb.y, maxb.z);

    glVertex3f(minb.x, minb.y, minb.z);
    glVertex3f(minb.x, minb.y, maxb.z);

    glVertex3f(maxb.x, minb.y, minb.z);
    glVertex3f(maxb.x, minb.y, maxb.z);

    glEnd();
}

Point Box::Center() const
{
    return (Point((maxb.x+minb.x)/2.,(maxb.y+minb.y)/2.,(maxb.z+minb.z)/2.));
}


//algoritmo de Haines
bool Box::intersects(const Ray &ray, float tmin, float tmax) const
{
    vector<Plane> planes = Planes();
    float near = FLT_MIN;
    float far = FLT_MAX;
    //cerr << "???" << endl;
    for (unsigned int i = 0; i < planes.size(); i++) {
        if (!planes[i].intersect(ray,near,far))
            return false;
    }
    return !(near > tmax || far < tmin);
}

bool Box::contains(const Point &p) const
{
    if ( p.x < minb.x ) return false;
    if ( p.x > maxb.x ) return false;
    if ( p.y < minb.y ) return false;
    if ( p.y > maxb.y ) return false;
    if ( p.z < minb.z ) return false;
    if ( p.z > maxb.z ) return false;
    return true;
}
